import { Injectable } from '@nestjs/common';
import { Menu_Create_Dto, Menu_Update_Dto } from './assets/menu.dto';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Menu } from './assets/menu.entity';
import { util_Db_Add, util_Db_AddAnyWhere } from '@/common/util/db';
import { Menu_Find_Dto } from './assets/menu.dto';
import { UserAdmin_Service } from '../userAdmin/userAdmin.service';
import { Role_Service } from '../role/role.service';
import { IRequest } from '@/common/typeScripts/index';
import { Class_HttpException_Base } from '@/common/classes/httpException';

@Injectable()
export class Menu_Service {
  constructor(
    private userAdmin_Service: UserAdmin_Service,
    private role_Service: Role_Service,
    @InjectRepository(Menu)
    private menu_Repository: Repository<Menu>,
  ) {}

  menu_BuildMenuTree(menus: Menu[], key?: string): Menu[] {
    const menuMap: { [key: number]: Menu & { children: Menu[] } } = {};
    menus.forEach((menu) => {
      menuMap[menu.id] = { ...menu, children: [] };
    });
    const rootMenus: Menu[] = [];
    menus.forEach((menu) => {
      if (menu.parent) {
        const keyed = key ? (menu.parent as unknown as string) : menu.parent.id;
        if (menuMap[keyed]) {
          menuMap[keyed].children.push(menuMap[menu.id]);
        }
      } else {
        rootMenus.push(menuMap[menu.id]);
      }
    });
    return rootMenus;
  }

  async menu_Slider(req: IRequest) {
    const userAdminId = req.user.userId;
    const userAdmin = await this.userAdmin_Service.userAdmin_FindOneByQuery({ id: userAdminId });
    const role = await this.role_Service.role_FindMenu(userAdmin.role.id);
    return this.menu_BuildMenuTree(role.menu);
  }

  async menu_Route(req: IRequest) {
    const userAdminId = req.user.userId;
    const userAdmin = await this.userAdmin_Service.userAdmin_FindOneByQuery({ id: userAdminId });
    if (!userAdmin || !userAdmin.statusUser) {
      throw new Class_HttpException_Base('该用户被删除或拉黑');
    }
    const role = await this.role_Service.role_Menu_Route(userAdmin.role.id);
    return role.menu;
  }

  async menu_Create(body: Menu_Create_Dto) {
    let parent;
    if (body.parentId) {
      parent = this.menu_Repository.create({ id: body.parentId });
    }
    return await util_Db_Add({
      createDto: { ...body, parent: parent ? parent : undefined },
      repository: this.menu_Repository,
    });
  }

  async menu_FindAllSelect() {
    const list = await this.menu_Repository
      .createQueryBuilder('menu')
      .leftJoin('menu.parent', 'parent')
      .select(['menu.id AS id', 'menu.id AS value', 'menu.menuName AS label', 'menu.parent AS parent'])
      .orderBy('value', 'DESC')
      .orderBy('menu.menuOrder', 'ASC')
      .getRawMany();
    return this.menu_BuildMenuTree(list, 'parent');
  }

  async menu_FindByPage(query: Menu_Find_Dto) {
    const { menuName } = query;
    const obj = {
      'menu.menuName': menuName,
    };
    // gg 选出parent对象
    const queryBuilder = this.menu_Repository
      .createQueryBuilder('menu')
      // gg 几种leftjoin的区别
      .leftJoinAndSelect('menu.parent', 'parent'); // 使用leftJoin而不是leftJoinAndSelect
    const list = await util_Db_AddAnyWhere<Menu>({ queryBuilder, obj })
      // gg 如何集体设置排序  根据传入参数的形式
      .orderBy('menu.id', 'DESC')
      .orderBy('menu.menuOrder', 'ASC')
      // gg getMany和getRawMany的区别
      .getMany();
    list.map((item: any) => {
      if (!item.parent) return;
      item.parentId = item.parent.id;
      item.parentMenuName = item.parent.menuName;
    });
    const menuList = this.menu_BuildMenuTree(list);
    return {
      totalElements: await this.menu_Repository.count(),
      list: menuList,
    };
  }

  async menu_Update(body: Menu_Update_Dto) {
    if (!body.id) {
      throw new Class_HttpException_Base('缺少更新的记录主键');
    }
    if (body.parentId == body.id) return new Class_HttpException_Base('自身不能作为父级菜单');
    const menued = this.menu_Repository.create(body);
    if (body.parentId) {
      const menu = this.menu_Repository.create({ id: body.parentId });
      menued.parent = menu;
    }
    // gg得加await 不然获取的时候会参数不对
    await this.menu_Repository.save(menued);
    return '编辑菜单成功';
  }

  async menu_Remove(id: number) {
    const data = await this.menu_Repository
      .createQueryBuilder('menu')
      .where('menu.parentId = :id', { id })
      .getOne();
    if (data) {
      throw new Class_HttpException_Base('不可删除含有子菜单的菜单');
    }
    await this.menu_Repository.delete(id);
    return '删除菜单成功';
  }
}
